package com.learn.cloud.validator.code;


import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.TypeUtil;
import com.learn.cloud.validator.annotation.ActivateValidation;
import com.learn.cloud.validator.annotation.ValidationHandler;
import com.learn.cloud.validator.utils.ReflectUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Configuration;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * 注册处理器
 * @description: 校验处理器
 * @author: cong zhi
 * @createDate: 2022/2/6 0:32
 * @updateUser: cong zhi
 * @updateDate: 2022/2/6 0:32
 * @updateRemark: 修改内容
 * @version: v1.0
 */
@Slf4j
@Configuration
public class ValidationProxyProcessor implements BeanPostProcessor {
    /**
     * postProcessAfterInitialization 当bean创建完毕后触发
     * 实例化、依赖注入完毕，在调用显示的初始化之前完成一些定制的初始化任务
     * 注意：方法返回值不能为null
     * 如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
     * 因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中
     *
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        /*log.info("初始化 before--实例化的bean对象:" + bean + "\t" + beanName);*/
        Object proxy = proxy(bean, beanName);
        if (ObjectUtil.isNotEmpty(proxy)) {
            return proxy;
        }
        registerHandler(bean, beanName);
        return bean;
    }

    private void registerHandler(Object bean, String beanName) {
        if (bean instanceof ValidationRuleHandler) {
            ValidationHandler annotation = bean.getClass().getAnnotation(ValidationHandler.class);
            if (ObjectUtil.isNotEmpty(annotation)) {
                Type typeArgument = TypeUtil.getTypeArgument(bean.getClass(), 0);
                Class<Annotation> aClass = (Class<Annotation>) TypeUtil.getClass(typeArgument);
                ValidationRulePool.registerRule(aClass, (ValidationRuleHandler<?>) bean, annotation.order());
            }
        }
    }

    private Object proxy(Object bean, String beanName) {
        // 获取该bean的方法
        Class<?> clazz = bean.getClass();
        Method[] hasAnnotationMethods = ReflectUtils.getHasAnnotationMethods(clazz, ActivateValidation.class);
        boolean clazzHashAnnotation = ReflectUtils.classHasAnnotation(clazz, ActivateValidation.class);
        if (clazzHashAnnotation) {
            hasAnnotationMethods = Arrays
                    .stream(clazz.getMethods())
                    .filter(method -> !Modifier.isStatic(method.getModifiers()))
                    .toArray(Method[]::new);
        }
        if (hasAnnotationMethods.length > 0) {
            Map<Method, List<Annotation>[]> methodMap = Arrays.stream(hasAnnotationMethods)
                    .collect(Collectors.toMap(Function.identity(), ReflectUtils::methodAnnotations));
            ValidationProxyHandler validationProxyHandler = new ValidationProxyHandler(bean, methodMap);
            return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), validationProxyHandler);
        }
        return null;
    }
}
